package com.demo.aidroid.services;

import android.app.Service;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.support.annotation.IntDef;
import android.util.Log;

import com.demo.aidroid.R;
import com.demo.aidroid.util.JsonParser;
import com.iflytek.cloud.ErrorCode;
import com.iflytek.cloud.InitListener;
import com.iflytek.cloud.RecognizerListener;
import com.iflytek.cloud.RecognizerResult;
import com.iflytek.cloud.SpeechConstant;
import com.iflytek.cloud.SpeechError;
import com.iflytek.cloud.SpeechRecognizer;
import com.iflytek.cloud.SpeechSynthesizer;
import com.iflytek.cloud.SynthesizerListener;

import org.json.JSONException;
import org.json.JSONObject;

import java.util.HashMap;
import java.util.LinkedHashMap;

public class IflyEngineService extends Service {

    private static final String TAG = IflyEngineService.class.getSimpleName();

    public static final int Listen_wake_up = 0x3001;
    public static final int Listen_recognize = 0x3002;
    public static final int Begin_recognize = 0x3004;
    public static final int VolumeChanged_recognize = 0x3008;

    public static final int Speak_opening_remarks = 0x4001;
    public static final int Speak_search_result = 0x4002;

    public static final int Speak_too_weak = 0x4003;



    private Messenger mMessenger = null;
    private Messenger clientMessenger = null;

    /**
     * 引擎类型
     */
    private final static String mEngineType = SpeechConstant.TYPE_CLOUD;
    /*
     * 语音听写对象
     */
    private SpeechRecognizer mIat;
    /*
     * 语音合成对象
     */
    private SpeechSynthesizer mTts;

    /**
     * 听写结果
     */
    private HashMap<String, String> mIatResults = new LinkedHashMap<>();

    String strResult = "";

    private int type = Listen_wake_up;

    @Override
    public IBinder onBind(Intent intent) {
        mMessenger = new Messenger(handler);
        return mMessenger.getBinder();
    }

    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            clientMessenger = msg.replyTo;
            switch (msg.what) {
                case Listen_wake_up:
                    startListening(Listen_wake_up);
                    break;
                case Speak_opening_remarks:
                    if (type != Listen_wake_up) {
                        return;
                    }
                    String openingWords = msg.getData().getString("openingRemarks");
                    startSpeaking(openingWords, Speak_opening_remarks);
                    break;
                case Speak_search_result:
                    String resultString = msg.getData().getString("resultString");
                    startSpeaking(resultString, Speak_search_result);
                    break;
            }
            super.handleMessage(msg);
        }
    };

    @Override
    public void onCreate() {
        super.onCreate();
        //  初始化识别对象
        mIat = SpeechRecognizer.createRecognizer(this, mIatInitListener);
        //  初始化合成对象
        mTts = SpeechSynthesizer.createSynthesizer(this, mTtsInitListener);

    }


    private void startListening(int type){
        this.type = type;
        if (type == Listen_recognize) {
            setRecognizeTimeOut();
        }
        if (mIat != null) {
            mIat.startListening(recognizerListener);
        }
    }

    private void stopListening() {
        if (mIat.isListening()) {
            mIat.stopListening();
        }
    }

    private void startSpeaking(String str,int type) {
        this.type = type;
        if (mTts != null) {
            mTts.startSpeaking(str, synthesizerListener);
        }
    }

    private void stopSpeaking(){
        if (mTts.isSpeaking()) {
            mTts.stopSpeaking();
        }
    }

    /**
     * 语音识别
     */
    private RecognizerListener recognizerListener = new RecognizerListener() {
        @Override
        public void onVolumeChanged(int i, byte[] bytes) {
            Log.d(TAG, "volume :" + i);
            if (type == Listen_recognize) {
                Message message = Message.obtain();
                Bundle bundle = new Bundle();
                bundle.putInt("volume",i);
                message.setData(bundle);
                message.what = VolumeChanged_recognize;
                try {
                    clientMessenger.send(message);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }

        }

        @Override
        public void onBeginOfSpeech() {
            Log.d(TAG, "begin recognize...");
            if (type == Listen_recognize) {
                Message message = Message.obtain();
                message.what = Begin_recognize;
                try {
                    clientMessenger.send(message);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }

        }

        @Override
        public void onEndOfSpeech() {
            Log.d(TAG, "end recognize.");
            Log.d(TAG, "voice input string:" + strResult);

            Message message = Message.obtain();
            Bundle bundle = new Bundle();
            bundle.putString("resultString",strResult);
            message.setData(bundle);
            if (type == Listen_wake_up) {
                message.what = Listen_wake_up;
                try {
                    clientMessenger.send(message);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
            if (type == Listen_recognize) {
                message.what = Listen_recognize;
                try {
                    clientMessenger.send(message);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        }

        @Override
        public void onResult(RecognizerResult recognizerResult, boolean isLast) {
            getResult(recognizerResult);
            if (isLast){

            }
        }

        @Override
        public void onError(SpeechError speechError) {
            Log.e(TAG, speechError.getPlainDescription(true));
            if (speechError.getErrorCode() == 10118) {
                if(type == Listen_recognize)
                    startSpeaking(getString(R.string.sorry), Speak_too_weak);
                else {
                    startListening(type);
                }
            }
        }

        @Override
        public void onEvent(int i, int i1, int i2, Bundle bundle) {

        }
    };

    /**
     * 语音合成
     */
    private SynthesizerListener synthesizerListener = new SynthesizerListener() {
        @Override
        public void onSpeakBegin() {
            Log.d(TAG, "begin synthesize...");
        }

        @Override
        public void onBufferProgress(int percent, int beginPos, int endPos, String info) {
            Log.d(TAG, "buffer progress :" + String.format(getString(R.string.tts_toast_format),
                    percent, beginPos));
        }

        @Override
        public void onSpeakPaused() {
            Log.d(TAG, "speak paused.");
        }

        @Override
        public void onSpeakResumed() {
            Log.d(TAG, "speak resumed.");
        }

        @Override
        public void onSpeakProgress(int percent, int beginPos, int endPos) {
            Log.d(TAG, "speak progress :" + String.format(getString(R.string.tts_toast_format),
                    percent, beginPos));
        }

        @Override
        public void onCompleted(SpeechError speechError) {
            if (speechError != null)
                return;
            if (null == mIat) {
                // 创建单例失败，与 21001 错误为同样原因，参考 http://bbs.xfyun.cn/forum.php?mod=viewthread&tid=9688
                Log.e(TAG, "创建对象失败，请确认 libmsc.so 放置正确，且有调用 createUtility 进行初始化");
                return;
            }

            strResult = "";
            mIatResults.clear();
            if (type == Speak_opening_remarks) {
                startListening(Listen_recognize);
            }
            if (type == Speak_search_result || type == Speak_too_weak) {
                startListening(Listen_wake_up);
            }
        }

        @Override
        public void onEvent(int i, int i1, int i2, Bundle bundle) {

        }
    };

    private void getResult(RecognizerResult results) {
        String text = JsonParser.parseIatResult(results.getResultString());

        String sn = null;
        // 读取json结果中的sn字段
        try {
            JSONObject resultJson = new JSONObject(results.getResultString());
            sn = resultJson.optString("sn");
        } catch (JSONException e) {
            e.printStackTrace();
        }

        mIatResults.put(sn, text);

        StringBuilder resultBuffer = new StringBuilder();
        for (String key : mIatResults.keySet()) {
            resultBuffer.append(mIatResults.get(key));
        }

        strResult = resultBuffer.toString();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (null != mIat) {
            // 退出时释放连接
            mIat.cancel();
            mIat.destroy();
        }

        if (null != mTts) {
            mTts.stopSpeaking();
            mTts.destroy();
        }
    }

    /**
     * 初始化语音识别监听器。
     */
    private InitListener mIatInitListener = new InitListener() {

        @Override
        public void onInit(int code) {
            if (code != ErrorCode.SUCCESS) {
                Log.e(TAG, "错误码：" + code);
            } else {
                setIatParam();
            }
        }
    };

    /**
     * 初始化语音合成监听器。
     */
    private InitListener mTtsInitListener = new InitListener() {
        @Override
        public void onInit(int code) {
            if (code != ErrorCode.SUCCESS) {
                Log.e(TAG, "错误码：" + code);
            } else {
                setTtsParams();
            }

            // 初始化成功，之后可以调用startSpeaking方法
            // 注：有的开发者在onCreate方法中创建完合成对象之后马上就调用startSpeaking进行合成，
            // 正确的做法是将onCreate中的startSpeaking调用移至这里
        }
    };

    /**
     * 设置语音识别参数
     */
    private void setIatParam() {
        // 清空参数
        mIat.setParameter(SpeechConstant.PARAMS, null);
        // 设置听写引擎
        mIat.setParameter(SpeechConstant.ENGINE_TYPE, mEngineType);
        // 设置返回结果格式
        mIat.setParameter(SpeechConstant.RESULT_TYPE, "json");
        // 设置语言
        mIat.setParameter(SpeechConstant.LANGUAGE, "zh_cn");
        // 设置语音前端点:静音超时时间，即用户多长时间不说话则当做超时处理
        mIat.setParameter(SpeechConstant.VAD_BOS, "4000");
        // 设置语音后端点:后端点静音检测时间，即用户停止说话多长时间内即认为不再输入， 自动停止录音
        mIat.setParameter(SpeechConstant.VAD_EOS, "1000");
        // 设置标点符号,设置为"0"返回结果无标点,设置为"1"返回结果有标点
        mIat.setParameter(SpeechConstant.ASR_PTT, "0");
    }

    /**
     * 设置语音合成参数
     */
    private void setTtsParams() {
        // 清空参数
        mTts.setParameter(SpeechConstant.PARAMS, null);
        mTts.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD);
        // 设置在线合成发音人
        mTts.setParameter(SpeechConstant.VOICE_NAME, "xiaoyan");
        //设置合成语速
        mTts.setParameter(SpeechConstant.SPEED, "50");
        //设置合成音调
        mTts.setParameter(SpeechConstant.PITCH, "50");
        //设置合成音量
        mTts.setParameter(SpeechConstant.VOLUME, "50");
        //设置播放器音频流类型
        mTts.setParameter(SpeechConstant.STREAM_TYPE, "3");
        // 设置播放合成音频打断音乐播放，默认为true
        mTts.setParameter(SpeechConstant.KEY_REQUEST_FOCUS, "true");
    }

    private void setRecognizeTimeOut(){
        // 设置语音前端点:静音超时时间，即用户多长时间不说话则当做超时处理
        mIat.setParameter(SpeechConstant.VAD_BOS, "8000");
        // 设置语音后端点:后端点静音检测时间，即用户停止说话多长时间内即认为不再输入， 自动停止录音
        mIat.setParameter(SpeechConstant.VAD_EOS, "2000");
    }
}
